package cn.snmp.mutual.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;

import cn.snmp.mutual.data.ErrorObjService;
import cn.snmp.mutual.common.snmp.SnmpNioTarget;
import cn.snmp.mutual.common.snmp.SnmpNioTargetUtilities;
import cn.snmp.mutual.constants.NnTempLetError;
import cn.snmp.mutual.nms.SnmpOID;
import cn.snmp.mutual.nms.SnmpVar;
import cn.snmp.mutual.nms.SnmpVarBind;
import lombok.extern.slf4j.Slf4j;
import cn.snmp.mutual.data.ObjService;
import cn.snmp.mutual.order.AbstractVarBindOrder;
import cn.snmp.mutual.util.OperatorUtilities;

/**
 * @since 2018.9.11
 * @author dengkn
 * Set Device Data ，下发数据拼装类
 */
@Slf4j
public class SetInfoHandler {
    private ErrorObjService result;
    private SnmpNioTarget snt;
    private String tableType;
    private List<SnmpVarBind> bindsList;
    private LinkedList mibNodeVector;
    private LinkedList statuNodeVector;
    private String[] nodeOIDs;
    private String[] nodeLogicNames;
    private SnmpVar[] values;
    private ObjService osResult;
    //private static int mibNodeOperatorCount = 0;

    /**
     * @param osParams SnmpTarget实例
     * @param osParams 输入参数
     * @return snt  SnmpNioTarget
     */
    public SnmpNioTarget hander(ObjService osParams) {
        init(osParams);
        int rowSetSize = osParams.objectSize("RowSet");
        if (rowSetSize == 0) {
            log.error("Configure the device, do you not configure data, tease me!");
            result.setValue("ErrCode", "801");
            result.setValue("ErrDesc", "Configure the device, do you not configure data, tease me!");
            return snt;
        }
        for (int rss = 0; rss < rowSetSize; rss++) {
            ObjService rowSetObject = osParams.objectAt("RowSet", rss);
            mibNodeVector = new LinkedList();
            statuNodeVector = new LinkedList();
            if (!keyConfig(rowSetObject) || isNodeCounNull() || isMibNodeOidNull(rowSetObject, osResult)) {
                return snt;
            }
            int blength = nodeOIDs.length;
            for (int i = 0; i < blength; i++) {
                SnmpOID oid = new SnmpOID(nodeOIDs[i]);
                SnmpVar var = values[i];
                bindsList.add(new SnmpVarBind(oid, var));
            }
        }
        try {
            SnmpVarBind[] binds = new SnmpVarBind[bindsList.size()];
            bindsList.toArray(binds);
            if (binds.length == 0) {
                result.setValue("ErrCode", "801");
                result.setValue("ErrDesc", "Do not have oid and oid value");
                snt.setFinishTag(true);
                log.error("Do not have oid and oid value");
                return snt;
            }
            AbstractVarBindOrder order = AbstractVarBindOrder.getVarBindOrder(osParams, osResult);
            if (order != null)
                binds = order.order(binds);
            snt.setBinds(binds);
        } catch (Exception e) {
            result.setValue("ErrCode", "801");
            result.setValue("ErrDesc", e.getMessage());
            log.error("ErrCode 801", e);
            snt.setFinishTag(true);
        }
        return snt;
    }


    private void init(ObjService osParams) {
        result = new ErrorObjService();
        snt = getSnmpTarget(osParams);
        initOsResult(osParams);
        snt.setResult(result);
        snt.setSNMPOpType(SnmpNioTarget.SNMP_SET_INFO);
        snt.setCommunity(osParams.getStringValue("WriteCommunity"));
        tableType = osResult.getStringValue("Type");
        bindsList = new ArrayList<SnmpVarBind>();
    }

    private void initOsResult(ObjService osParams) {
        osResult = osParams.objectAt("MIB", 0);
        for (int i = 0; i < osResult.rowSize("MibTable"); i++) {
            if (osResult.objectAt("MibTable", i).getStoreValueMap().get("Name")
                    .equals((String) osParams.getValue("TableName"))) {
                osResult = osResult.objectAt("MibTable", i);
                break;
            }
        }
    }

    private boolean keyConfig(ObjService rowSetObject) {
        for (Object mapKey : rowSetObject.getCurrentHashMap().keySet()) {
            String strlogic = (String) mapKey;
            if (strlogic.equals("Instance"))
                continue;
            ObjService mibNode = OperatorUtilities.findMibNode(osResult, strlogic);
            if (mibNode == null) {
                log.error("MibNode not defined in ConfigFile");
                snt.setFinishTag(true);
                result.setValue("isFinish", "true");
                result.setErrCode("" + NnTempLetError.MIB_NODE_NOT_FOUND);
                result.setErrDesc(strlogic + " not defined in ConfigFile.");
                snt.setResult(result);
                return false;
            }
            if (mibNode.getStringValue("Oid").equals(""))
                continue;
            if (mibNode.getStringValue("IsStatus").equalsIgnoreCase("true"))
                statuNodeVector.add(mibNode);
            else
                mibNodeVector.add(mibNode);
        }
        return true;
    }

    private boolean isNodeCounNull() {
        int size = mibNodeVector.size() + statuNodeVector.size();
        if (size == 0) {
            log.error("mutual node not found!");
            snt.setFinishTag(true);
            result.setValue("isFinish", "true");
            result.setValue("ErrCode", "" + NnTempLetError.SNMP_NODE_NOT_FOUND);
            result.setValue("ErrDesc", "Not found node");
            return true;
        }
        return false;
    }

    private boolean isMibNodeOidNull(ObjService rowSetObject, ObjService osParams) {
        try {
            int size = mibNodeVector.size() + statuNodeVector.size();
            nodeOIDs = new String[size];
            nodeLogicNames = new String[size];
            values = new SnmpVar[size];
            valueConfig(rowSetObject, osParams);
            int mibNodeOperatorCount = 0;
            if (statuNodeVector.size() == 0) {

                for (int j = 0; j < mibNodeVector.size(); j++) {
                    ObjService mibNode = (ObjService) mibNodeVector.get(j);
                    String name = mibNode.getStringValue("Logic");
                    nodeLogicNames[mibNodeOperatorCount] = name;
                    HashMap table = rowSetObject.getCurrentHashMap();
                    Object value = table.get(nodeLogicNames[mibNodeOperatorCount]);
                    values[mibNodeOperatorCount] = OperatorUtilities.writeSnmpVar(value, mibNode, osParams, rowSetObject);
                    if (tableType.equalsIgnoreCase("List")) {
                        String instance = mibNode.getStringValue("Instance");
                        if (instance == null || "".equals(instance)) {
                            instance = "0";
                        }
                        nodeOIDs[mibNodeOperatorCount] = mibNode.getStringValue("OID") + "." + instance;
                    } else {
                        String nodeName = nodeLogicNames[mibNodeOperatorCount];
                        String instance = rowSetObject.getStringValue("Instance");
                        if (instance.equalsIgnoreCase("")) {
                            int pos = nodeName.indexOf(".");
                            nodeOIDs[mibNodeOperatorCount] = mibNode.getStringValue("OID") + nodeName.substring(pos);
                        } else {
                            nodeOIDs[mibNodeOperatorCount] = mibNode.getStringValue("OID") + "." + instance;
                        }
                    }
                    mibNodeOperatorCount++;
                }
                mibNodeOperatorCount = 0;

            } else {
                String instance = rowSetObject.getStringValue("Instance");
                for (int j = 0; j < mibNodeVector.size(); j++) {
                    ObjService mibNode = (ObjService) mibNodeVector.get(j);
                    String name = mibNode.getStringValue("Logic");

                    String nodeName = nodeLogicNames[j];
                    if (instance.equalsIgnoreCase("")) {
                        int pos = nodeName.indexOf(".");
                        nodeOIDs[j] = mibNode.getStringValue("OID") + nodeName.substring(pos);
                    } else {
                        nodeOIDs[j] = mibNode.getStringValue("OID") + "." + instance;
                    }
                }

                ObjService mibNode = (ObjService) statuNodeVector.get(0);
                String name = mibNode.getStringValue("Logic");
                nodeLogicNames[size - 1] = name;
                HashMap table = rowSetObject.getCurrentHashMap();
                Object value = table.get(nodeLogicNames[size - 1]);
                values[size - 1] = OperatorUtilities.writeSnmpVar(value, mibNode, osParams, rowSetObject);


                if (instance.equalsIgnoreCase("")) {
                    int pos = name.indexOf(".");
                    nodeOIDs[size - 1] = mibNode.getStringValue("OID") + name.substring(pos);
                } else {
                    nodeOIDs[size - 1] = mibNode.getStringValue("OID") + "." + instance;
                }
            }
        } catch (Exception e) {
            snt.setFinishTag(true);
            result.setValue("isFinish", "true");
            result.setErrCode("" + NnTempLetError.NETEMPLET_UNKNOWN_ERROR);
            result.setErrDesc(e.toString());
            snt.setResult(result);
            log.error("MibNode not defined Oid.", e);
            return true;
        }
        return false;
    }

    private void valueConfig(ObjService rowSetObject, ObjService osParams) {
        int mibNodeOperatorCount = 0;
        for (int j = 0; j < mibNodeVector.size(); j++) {
            ObjService mibNode = (ObjService) mibNodeVector.get(j);
            String name = mibNode.getStringValue("Logic");
            nodeLogicNames[mibNodeOperatorCount] = name;
            HashMap table = rowSetObject.getCurrentHashMap();
            Object value = table.get(nodeLogicNames[mibNodeOperatorCount]);
            values[mibNodeOperatorCount] = OperatorUtilities.writeSnmpVar(value, mibNode, osParams, rowSetObject);
            if (tableType.equalsIgnoreCase("List")) {
                nodeOIDs[mibNodeOperatorCount] = mibNode.getStringValue("OID") + "." + mibNode.getStringValue("Instance");
            } else {
                String nodeName = nodeLogicNames[mibNodeOperatorCount];
                String instance = rowSetObject.getStringValue("Instance");
                if (instance.equalsIgnoreCase("")) {
                    int pos = nodeName.indexOf(".");
                    nodeOIDs[mibNodeOperatorCount] = mibNode.getStringValue("OID") + nodeName.substring(pos);
                } else {
                    nodeOIDs[mibNodeOperatorCount] = mibNode.getStringValue("OID") + "." + instance;
                }
            }
            log.debug("logic [" + nodeLogicNames[mibNodeOperatorCount] + "], oid [" + nodeOIDs[mibNodeOperatorCount] + "], value ["
                    + values[mibNodeOperatorCount] + "]");
            mibNodeOperatorCount++;
        }
    }

    /**
     * @param snmpParam: snmp参数
     * @return 配置好的SnmpNioTarget信息
     */
    protected SnmpNioTarget getSnmpTarget(ObjService snmpParam) {
        SnmpNioTarget snmpTarget = null;
        try {
            snmpTarget = SnmpNioTargetUtilities.getSnmpNioTarget(snmpParam);
            SnmpNioTargetUtilities.initSnmpNioTarget(snmpTarget, snmpParam);
            return snmpTarget;
        } catch (Exception e) {
            log.error("You are wrong in configuring the operation information. Check it again.");
            log.error("init getSnmpTarget error!", e);
            snmpTarget = null;
            return snmpTarget;
        }
    }

}
